#ifndef _NETWORK_H
#define _NETWORK_H

#include <map>
#include <vector>
#include <queue>

#include "Messages.h"
#include "NetworkController.h"

#ifdef _DEBUG

#include <assert.h>
#include <iostream>
#define ASSERT(x) assert(x)

#else

#define ASSERT(x)

#endif

class SocketEUDP;

//Singleton Class
class Network
{
public:
	static Network *Create()
	{
		if(g_instance == NULL)
		{
			g_instance = new Network();
		}
		return g_instance;
	}
	static Network *Get()
	{
		ASSERT(g_instance != NULL);
		return g_instance;
	}
	static void Delete()
	{
		delete g_instance;
		g_instance = NULL;
	}

	void Initalise(bool isServer);
	bool IsServer(){ return m_isServer; }

	void AddNetworkController(NetworkController *controller);
	void UpdateTick(float deltaT);
	long GetCurrentTick(){return m_currentTick;}

	void ConnectTo(std::string ip, int port);
	void Disconnect();

	void SendEntity(char *data, int dataLength, short entityReference);
	void SendNewPlayer(char *data, int dataLength, short entityReference);
	void SendShot(char *data, int dataLength, short entityReference);

	int GetEventCount();
	GameMessage GetNextEvent();

	short GetThisClientReference();

	void PreUpdate();
	void PostUpdate();

private:
	static Network *g_instance;
	Network() : m_socket(NULL), m_currentTick(0), m_tickTimer(0.f)
	{
		/* nothing */
	}

	struct MessageWaiting
	{
		NM type;
		short reference;
		int length;
		char data[MAX_MESSAGE_SIZE];
	};

	void SendNewPlayerSingle(bool greet, int clientRef, char *data, int dataLength, short entityReference);
	bool SendToController(int entityRef, long tick, char *data);

	SocketEUDP *m_socket;
	bool m_isServer;

	long m_currentTick;
	float m_tickTimer;

	std::map<int, int> m_connections; //The connections list stores the EUDP ref in the first field, with the bound entity in the second field (only applicable as a server)

	std::vector<NetworkController*> m_controllers;
	std::queue<GameMessage> m_events; //Stores all messages that can't be sent to network controllers (must be processed by game itself)
	std::queue<MessageWaiting> m_messagesToSend;
};

#endif